Skip to content

fix(SelectLite): zoom 补偿修位置偏移 + 同步二次定位消除闪动 + 三平台统一#428

Merged
appergb merged 1 commit into
betafrom
fix/selectlite-zoom-offset
May 13, 2026
Merged

fix(SelectLite): zoom 补偿修位置偏移 + 同步二次定位消除闪动 + 三平台统一#428
appergb merged 1 commit into
betafrom
fix/selectlite-zoom-offset

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented May 13, 2026

User description

Summary

  • 修复 SelectLite 下拉位置右偏(v1.3.1-17 注释里那句"WKWebView 上 portal+position:fixed 反复修不干净"的真正根因)。fontScale.ts 用 html.style.zoom 整体缩放,WKWebView 在 zoom 下双标:getBoundingClientRect 返回 post-zoom 视觉坐标,但 position:fixedleft/top/width 被当 pre-zoom 布局坐标处理。修法是 positionPopover 里把视觉坐标除以 zoom 转回布局坐标再 setAnchor,浏览器渲染时 ×zoom 回到正确视觉位置。
  • 消除打开瞬间的位置闪动。之前 setPopoverRefrequestAnimationFrame 在 popover mount 后做第二次定位,但 RAF 在 paint 之后触发,造成「兜底位置 paint → 校正位置 paint」两帧闪动;短选项尤其明显(fallback popoverHeight=280 vs 真实 60~100px 让 flipUp 决策反转)。改用 popoverMounted state 翻 useLayoutEffect 依赖,两阶段定位都同步在 paint 前完成,单帧最终位置。
  • 删除 macOS 走原生 <select> 的分支。zoom 补偿到位后自定义 popover 在 mac 上严丝合缝对齐 trigger,三平台统一走自定义实现,视觉/键盘交互一致;同时清理 detectOS import。

Test plan

  • macOS:Settings 主窗口 → 提供商 → 「供应商」下拉,调试覆盖层验证 trigger / popover / 补偿位置三者对齐;下拉打开无闪动
  • npm run build (tsc && vite build) 通过
  • ./scripts/build-mac.sh 完整出 .app + .dmg,ad-hoc 签名校验通过
  • Windows:自检在 large 档(默认 zoom=1.1)下下拉对齐 trigger、无闪动
  • 不同 fontScale 档位(small=.9 / medium=1 / large=1.1)下都对齐

Root cause details

直接 setAnchor({ left: rect.left, ... }),popover 视觉位置 = rect.left × zoom,右偏 rect.left × (zoom-1)。trigger 越靠右、zoom 越大,偏移越大。Settings 弹窗里 rect.left ≈ 775zoom = 1.1 时偏 77.5 CSS px,跟用户截图实测一致。修法 setAnchor({ left: rect.left / zoom, ... }) 反向抵消即可。

🤖 Generated with Claude Code


PR Type

Bug fix, Enhancement


Description

  • Compensate zoom in popover positioning

  • Remove RAF-based second positioning

  • Eliminate macOS native <select> branch


Diagram Walkthrough

flowchart LR
  A["SelectLite dropdown"] --> B["Zoom compensation"]
  A --> C["Synchronous re-positioning"]
  A --> D["Remove macOS native branch"]
Loading

File Walkthrough

Relevant files
Bug fix
SelectLite.tsx
Fix positioning and unify dropdown rendering                         

openless-all/app/src/components/ui/SelectLite.tsx

  • Adds zoom compensation when calculating anchor coordinates and width.
  • Replaces RAF-based repositioning with popoverMounted-driven
    useLayoutEffect.
  • Removes the macOS native branch and detectOS import.
+47/-60 

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 13, 2026

PR Reviewer Guide 🔍

(Review updated until commit 424d973)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

[zoom 偏移 — 真凶]
fontScale.ts 通过 html.style.zoom 整体缩放页面(small=.9 / medium=1 / large=1.1)。
WKWebView 在 zoom 下双标:getBoundingClientRect 返回 post-zoom(视觉)坐标,
而 position:fixed 的 left/top/width 被当 pre-zoom(布局)坐标处理。直接
`left = rect.left` 让 popover 视觉位置 = rect.left × zoom,右偏
rect.left × (zoom-1) 像素。trigger 越靠右、zoom 越大,偏移越大。

修法:positionPopover 拿到 rect 后,把视觉坐标除以 zoom 转回布局坐标再
setAnchor,浏览器渲染时 ×zoom 后回到正确视觉位置。这是 v1.3.1-17 注释里
那句"WKWebView 里 portal+position:fixed 的自定义 popover 位置漂移反复修
不干净"的真正根因——前几位修过的人没意识到 zoom 是分母。

[闪动]
之前 setPopoverRef 用 requestAnimationFrame 在 popover mount 后再校正一次
位置,但 RAF 在 paint 之后触发,导致「兜底位置 paint → 校正位置 paint」
两帧闪动。短选项尤其明显(fallback popoverHeight=280 vs 真实 60~100px 让
flipUp 决策反转)。改用 popoverMounted state 翻 useLayoutEffect 的依赖,
两阶段定位都同步在 paint 前完成,用户只看到一帧最终位置。

[移除 mac native 分支]
v1.3.1-17 因为上述偏移修不干净,把 macOS 改走原生 <select>(NSPopUpButton)。
zoom 补偿到位后自定义 popover 在 mac 上对齐 trigger,删掉 mac 原生分支
(含 detectOS import),三平台统一走自定义实现,视觉/键盘交互一致。
@appergb appergb force-pushed the fix/selectlite-zoom-offset branch from e216e70 to 424d973 Compare May 13, 2026 06:10
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 424d973

@appergb appergb merged commit 1f2b259 into beta May 13, 2026
4 checks passed
@appergb appergb deleted the fix/selectlite-zoom-offset branch May 13, 2026 06:25
appergb pushed a commit that referenced this pull request May 13, 2026
bump 1.3.1-18 → 1.3.1-19,6 处版本号手动同步(bump-version.sh regex 不收
Beta 版本号):package.json / package-lock.json (root+nested) / tauri.conf.json
/ Cargo.toml / Cargo.lock(openless)。

[变更]
- SelectLite 下拉位置在 html.zoom != 1 下不再右偏(fontScale 的 large 档影响
  最大);CSS zoom 在 WKWebView 下让 getBoundingClientRect 返回 post-zoom
  坐标但 position:fixed 用 pre-zoom 坐标,positionPopover 现在补偿 zoom 转回。
- 下拉打开瞬间的位置闪动消除(popoverMounted state 触发 useLayoutEffect 同步
  二次定位,替代 requestAnimationFrame 的 post-paint 校正)。
- 移除 macOS 走原生 <select> 的旁路分支,三平台统一自定义 popover。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant